package com.nineclock.sign.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.support.ExcelTypeEnum;
import com.alibaba.excel.write.metadata.style.WriteCellStyle;
import com.alibaba.excel.write.metadata.style.WriteFont;
import com.alibaba.excel.write.style.HorizontalCellStyleStrategy;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.nineclock.attendance.dto.AttendPunchDTO;
import com.nineclock.attendance.dto.AttendsDTO;
import com.nineclock.attendance.pojo.AttendPunch;
import com.nineclock.common.entity.PageResult;
import com.nineclock.common.entity.UserInfo;
import com.nineclock.common.enums.ResponseEnum;
import com.nineclock.common.exception.NcException;
import com.nineclock.common.threadlocal.CurrentUserHolder;
import com.nineclock.common.utils.BeanHelper;
import com.nineclock.common.utils.DateTimeUtil;
import com.nineclock.document.pojo.DocCollaborations;
import com.nineclock.sign.dto.SignAllUserDTO;
import com.nineclock.sign.dto.SignDTO;
import com.nineclock.sign.dto.SignInfoDTO;
import com.nineclock.sign.dto.SignPCListDTO;
import com.nineclock.sign.excel.CustomStyle;
import com.nineclock.sign.mapper.SignInfoMapper;
import com.nineclock.sign.mapper.SignPictureMapper;
import com.nineclock.sign.pojo.SignInfo;
import com.nineclock.sign.pojo.SignPicture;
import com.nineclock.sign.service.SignService;
import com.nineclock.system.dto.SysCompanyUserDTO;
import com.nineclock.system.dto.SysDepartmentDTO;
import com.nineclock.system.feign.SysUserFeign;
import org.apache.poi.ss.usermodel.HorizontalAlignment;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.*;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

@Service
@Transactional
public class SignServiceImpl implements SignService {

    @Autowired
    SignInfoMapper signInfoMapper;
    @Autowired
    RedisTemplate redisTemplate;
    @Autowired
    SignPictureMapper pictureMapper;

    //签到模块
    @Override
    public void signInsert(SignDTO signDTO) {
        if (ObjectUtil.isNull(signDTO)) {
            throw new NcException(ResponseEnum.SIGN_DATA_NULL);
        }
        //补全组装数据
        SignInfo signInfo = BeanHelper.copyProperties(signDTO, SignInfo.class);

        signInfo.setCompanyId(CurrentUserHolder.get().getCompanyId());
        signInfo.setCompanyUserId(CurrentUserHolder.get().getCompanyUserId());
        signInfo.setCreateTime(new Date());
        signInfo.setCreateDate(DateTimeUtil.dateToStr(new Date(),DateTimeUtil.TIME_FORMAT_2));
        signInfo.setCreateMonth(DateTimeUtil.dateToStr(new Date(),DateTimeUtil.TIME_FORMAT_4));
        signInfoMapper.insert(signInfo);
        String[] split = signDTO.getImages().split(",");
        //插入图片记录
        for (String s : split) {
            SignPicture signPicture = new SignPicture();
            signPicture.setSignId(signInfo.getId());
            signPicture.setUrl(s);
            pictureMapper.insert(signPicture);
        }

        Long companyUserId = CurrentUserHolder.get().getCompanyUserId();
        //存入redis缓存
        String key = signInfo.getCreateDate() + companyUserId;
        if (redisTemplate.boundValueOps(key).get() == null) {
            redisTemplate.boundValueOps(key).set(1);
        } else {
            Integer count = (Integer) redisTemplate.boundValueOps(key).get() + 1;
            redisTemplate.boundValueOps(key).set(count);
        }

    }

    //获取当前用户当日签到次数
    @Override
    public Integer getDayCount() {
        Long companyUserId = CurrentUserHolder.get().getCompanyUserId();
        String key = DateTimeUtil.dateToStr(new Date(), DateTimeUtil.TIME_FORMAT_2) + companyUserId;

        Integer dayCount = (Integer) redisTemplate.boundValueOps(key).get();

        return dayCount;
    }


    //导出签到列表
    @Override
    public void export(String startTime, String endTime) throws IOException {
        //获取response对象 , 设置响应头信息
        HttpServletResponse response = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getResponse();
        response.setHeader("Content-Disposition", "attachment;filename=attendance.xls");
        response.setContentType("application/octet-stream;charset=UTF-8");

        //查询指定时间范围内的考勤打卡数据
        List<SignPCListDTO> signPCListDTOList = this.querySignList(startTime, endTime, null, null).getRows();

        //通过EasyExcel的API生成文件, 并通过流的形式输出
        EasyExcel.write(response.getOutputStream())
                .excelType(ExcelTypeEnum.XLS)

                .registerWriteHandler(new CustomStyle())//设置列宽
                .registerWriteHandler(horizontalCellStyleStrategy())//设置字体样式

                .head(headers(signPCListDTOList))//表头
                .sheet("签到列表")
                .doWrite(getData(signPCListDTOList));//表数据
    }

    //获取表数据
    private List<List<String>> getData(List<SignPCListDTO> signPCListDTOS) {
        List<List<String>> dataList = new ArrayList<>();

        if (CollectionUtil.isNotEmpty(signPCListDTOS)) {
            signPCListDTOS.stream().forEach(signPCListDTO -> {
                List<String> rowList = new ArrayList<>();

                rowList.add(signPCListDTO.getUserName());
                rowList.add(signPCListDTO.getWorkNumber());
                rowList.add(signPCListDTO.getDepartment() == null ? "" : signPCListDTO.getDepartment().getName());
                rowList.add(signPCListDTO.getPost());

                List<SignInfoDTO> signs = signPCListDTO.getSigns();
                if (CollectionUtil.isNotEmpty(signs)) {
                    signs.stream().forEach(signInfoDTO -> {
                        rowList.add(signInfoDTO.getSignCount().toString());
                    });
                }
                dataList.add(rowList);
            });
        }

        return dataList;
    }

    //设置表头
    private List<List<String>> headers(List<SignPCListDTO> signPCListDTOS) {
        List<List<String>> headers = new ArrayList<>();
        headers.add(Arrays.asList("姓名"));
        headers.add(Arrays.asList("工号"));
        headers.add(Arrays.asList("部门"));
        headers.add(Arrays.asList("职位"));

        if (CollectionUtil.isNotEmpty(signPCListDTOS)) {
            SignPCListDTO signPCListDTO = signPCListDTOS.get(0);
            List<SignInfoDTO> signs = signPCListDTO.getSigns();

            if (CollectionUtil.isNotEmpty(signs)) {
                signs.stream().forEach(signInfoDTO -> headers.add(Arrays.asList(signInfoDTO.getSignDate())));
            }
        }

        System.out.println("Headers: " + headers);
        return headers;
    }

    //设置样式
    public HorizontalCellStyleStrategy horizontalCellStyleStrategy() {
        WriteCellStyle contentWriteCellStyle = new WriteCellStyle();
        //内容策略 - 水平居中
        contentWriteCellStyle.setHorizontalAlignment(HorizontalAlignment.CENTER);
        //设置字体
        WriteFont font = new WriteFont();
        font.setFontName("阿里巴巴普惠体");
        font.setFontHeightInPoints((short) 11);
        contentWriteCellStyle.setWriteFont(font);

        HorizontalCellStyleStrategy horizontalCellStyleStrategy = new HorizontalCellStyleStrategy(contentWriteCellStyle, contentWriteCellStyle);
        return horizontalCellStyleStrategy;
    }


    @Autowired
    private SysUserFeign sysUserFeign;

    //PC端查询签到列表
    @Override
    public PageResult<SignPCListDTO> querySignList(String startTime, String endTime, Integer page, Integer pageSize) {
        //参数校验
        if (StrUtil.isEmpty(startTime) || StrUtil.isEmpty(endTime)) {
            throw new NcException(ResponseEnum.INVALID_PARAM_ERROR);
        }
        ArrayList<SignPCListDTO> signPCListDTOS = new ArrayList<>();

        List<SignInfo> signInfos = signInfoMapper.selectList(null);
        Map<Long, List<SignInfo>> userSignInfo = signInfos.stream().collect(Collectors.groupingBy(SignInfo::getCompanyUserId));

        /*List<SysCompanyUserDTO> data = sysUserFeign.queryAllCompanyUser().getData();
        Set<Long> collect1 = data.stream().map(sysCompanyUserDTO -> {
            return sysCompanyUserDTO.getId();
        }).collect(Collectors.toSet());*/
        //
        for (Long userId : userSignInfo.keySet()) { //仅仅遍历signinfo表
        //for (Long userId : collect1) {  //遍历所有员工表
            //封装signPCListDTO
            SysCompanyUserDTO sysCompanyUserDTO = sysUserFeign.queryByCompanyUserId(userId).getData();
            if (sysCompanyUserDTO != null) {
                SignPCListDTO signPCListDTO = BeanHelper.copyProperties(sysCompanyUserDTO, SignPCListDTO.class);

                //private SysDepartmentDTO department;
                SysDepartmentDTO departmentDTO = new SysDepartmentDTO();
                departmentDTO.setId(sysCompanyUserDTO.getCompanyId());
                departmentDTO.setName(sysCompanyUserDTO.getDepartmentName());
                signPCListDTO.setDepartment(departmentDTO);

                //private List<SignInfoDTO> signs;
                LambdaQueryWrapper<SignInfo> queryWrapper = new LambdaQueryWrapper<>();
                queryWrapper.eq(SignInfo::getCompanyUserId, sysCompanyUserDTO.getId());
                queryWrapper.between(SignInfo::getCreateDate, startTime, endTime);
                List<SignInfo> signInfos1 = signInfoMapper.selectList(queryWrapper);
                //signPCListDTO.setSigns(BeanHelper.copyWithCollection(signInfos1, SignInfoDTO.class));
                //封装signPCListDTO.setSigns
                Map<String, List<SignInfo>> collect = signInfos1.stream().collect(Collectors.groupingBy(SignInfo::getCreateDate));
                //遍历时间区间
                ArrayList<SignInfoDTO> signInfoDTOS = new ArrayList<>();

                boolean flag = false;
                Set<String> strings = collect.keySet();
                List<Date> datesBetweenTwoDate = DateTimeUtil.getDatesBetweenTwoDate(startTime, endTime, "yyyy-MM-dd");
                for (Date date : datesBetweenTwoDate) {
                    if (strings.contains(DateTimeUtil.dateToStr(date, "yyyy-MM-dd"))) {
                        flag = true;
                        SignInfoDTO signInfoDTO = new SignInfoDTO();
                        signInfoDTO.setSignDate(DateTimeUtil.dateToStr(date, "yyyy/MM/dd"));
                        signInfoDTO.setSignCount(collect.get(DateTimeUtil.dateToStr(date, "yyyy-MM-dd")).size());
                        signInfoDTOS.add(signInfoDTO);
                    } else {
                        SignInfoDTO signInfoDTO = new SignInfoDTO();
                        signInfoDTO.setSignDate(DateTimeUtil.dateToStr(date, "yyyy/MM/dd"));
                        signInfoDTO.setSignCount(0);
                        signInfoDTOS.add(signInfoDTO);
                    }
                }

                signPCListDTO.setSigns(signInfoDTOS);
                if (flag) {
                    signPCListDTOS.add(signPCListDTO);
                }
            }
        }


        if (page == null && pageSize == null) {
            return new PageResult<SignPCListDTO>(null, null, signPCListDTOS);
        }else{
            ArrayList<SignPCListDTO> signPCListDTOS1 = new ArrayList<>();
            for (int i = 0; i < signPCListDTOS.size(); i++) {
                int x = (page-1)*pageSize;
                if (i >= x && i < x + pageSize) {
                    signPCListDTOS1.add(signPCListDTOS.get(i));
                }
            }
            return new PageResult<SignPCListDTO>((long) signPCListDTOS.size(), (long) (Math.ceil(signPCListDTOS.size() / pageSize)+1), signPCListDTOS1);
        }
    }


    @Autowired
    private SignPictureMapper signPictureMapper;

    //APP端-查看所有员工指定日期签到列表
    @Override
    public List<SignAllUserDTO> listSignAllUser(String dateStr) {

        //参数校验
        if (StrUtil.isEmpty(dateStr)) {
            throw new NcException(ResponseEnum.INVALID_PARAM_ERROR);
        }

        //DateTime parse = DateUtil.parse(dateStr);
        LambdaQueryWrapper<SignInfo> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(SignInfo::getCompanyId, CurrentUserHolder.get().getCompanyId());
        queryWrapper.eq(SignInfo::getCreateDate, dateStr);
        List<SignInfo> signInfos = signInfoMapper.selectList(queryWrapper);

        Map<Long, List<SignInfo>> map = signInfos.stream().collect(Collectors.groupingBy(SignInfo::getCompanyUserId));

        ArrayList<SignAllUserDTO> signAllUserDTOS = new ArrayList<>();
        for (Long userId : map.keySet()) {
            SysCompanyUserDTO sysCompanyUserDTO = sysUserFeign.queryByCompanyUserId(userId).getData();
            if (sysCompanyUserDTO != null) {
                SignAllUserDTO signAllUserDTO = new SignAllUserDTO();
                signAllUserDTO.setUsername(sysCompanyUserDTO.getUserName());
                List<SignDTO> signDTOS = BeanHelper.copyWithCollection(map.get(userId), SignDTO.class);
                for (SignDTO signDTO : signDTOS) {
                    //封装当前日签到次数
                    LambdaQueryWrapper<SignInfo> wrapper = new LambdaQueryWrapper<>();
                    wrapper.eq(SignInfo::getCompanyId, CurrentUserHolder.get().getCompanyId());
                    wrapper.eq(SignInfo::getCompanyUserId, signDTO.getCompanyUserId());
                    wrapper.eq(SignInfo::getCreateDate, signDTO.getCreateDate());
                    Integer integer = signInfoMapper.selectCount(wrapper);
                    signDTO.setDayCount(integer+"");

                    //封装当前月签到次数
                    LambdaQueryWrapper<SignInfo> querywrapper = new LambdaQueryWrapper<>();
                    wrapper.eq(SignInfo::getCompanyId, CurrentUserHolder.get().getCompanyId());
                    wrapper.eq(SignInfo::getCompanyUserId, signDTO.getCompanyUserId());
                    List<SignInfo> signInfos1 = signInfoMapper.selectList(querywrapper);
                    Map<String, List<SignInfo>> collect = signInfos1.stream().collect(Collectors.groupingBy(SignInfo::getCreateMonth));
                    signDTO.setMonthCount(collect.get(signDTO.getCreateMonth()).size()+"");

                    //封装签到图片列表
                    LambdaQueryWrapper<SignPicture> wp = new LambdaQueryWrapper<>();
                    wp.eq(SignPicture::getSignId,signDTO.getId());
                    List<SignPicture> signPictures = signPictureMapper.selectList(wp);
                    List<String> picUrlList = signPictures.stream().map(signPicture -> {
                        return signPicture.getUrl();
                    }).collect(Collectors.toList());
                    signDTO.setSignPictureUrlList(picUrlList);

                }
                signAllUserDTO.setSignResponseList(signDTOS);
                signAllUserDTOS.add(signAllUserDTO);
            }
        }
        return signAllUserDTOS;
    }

    //当前用户当月所有签到记录
    @Override
    public List<SignDTO> findCurrentUserByMonth(String dateStr) {
        if (StringUtils.isEmpty(dateStr)){
            throw new NcException(ResponseEnum.INVALID_PARAM_ERROR);
        }

        LambdaQueryWrapper<SignInfo> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(SignInfo::getCreateMonth, dateStr);
        queryWrapper.eq(SignInfo::getCompanyUserId, CurrentUserHolder.get().getCompanyId());

        List<SignInfo> signInfos = signInfoMapper.selectList(queryWrapper);
        List<SignDTO> signDTOS = BeanHelper.copyWithCollection(signInfos, SignDTO.class);
        for (SignDTO signDTO : signDTOS) {
            //封装当前日签到次数
            LambdaQueryWrapper<SignInfo> wrapper = new LambdaQueryWrapper<>();
            wrapper.eq(SignInfo::getCompanyId, CurrentUserHolder.get().getCompanyId());
            wrapper.eq(SignInfo::getCompanyUserId, signDTO.getCompanyUserId());
            wrapper.eq(SignInfo::getCreateDate, signDTO.getCreateDate());
            Integer integer = signInfoMapper.selectCount(wrapper);
            signDTO.setDayCount(integer+"");

            //封装当前月签到次数
            LambdaQueryWrapper<SignInfo> querywrapper = new LambdaQueryWrapper<>();
            wrapper.eq(SignInfo::getCompanyId, CurrentUserHolder.get().getCompanyId());
            wrapper.eq(SignInfo::getCompanyUserId, signDTO.getCompanyUserId());
            List<SignInfo> signInfos1 = signInfoMapper.selectList(querywrapper);
            Map<String, List<SignInfo>> collect = signInfos1.stream().collect(Collectors.groupingBy(SignInfo::getCreateMonth));
            signDTO.setMonthCount(collect.get(signDTO.getCreateMonth()).size()+"");

            //封装签到图片列表
            LambdaQueryWrapper<SignPicture> wp = new LambdaQueryWrapper<>();
            wp.eq(SignPicture::getSignId,signDTO.getId());
            List<SignPicture> signPictures = signPictureMapper.selectList(wp);
            List<String> picUrlList = signPictures.stream().map(signPicture -> {
                return signPicture.getUrl();
            }).collect(Collectors.toList());
            signDTO.setSignPictureUrlList(picUrlList);

        }
        return signDTOS;
    }
}
